Obafemi Emmanuel

State Management in Flutter

Published 3 months ago

State management is a crucial aspect of Flutter app development. It determines how the application handles changes in data and UI updates. There are multiple approaches to state management in Flutter, each with its own advantages. In this article, we will explore:

  1. setState() - Managing Local State
  2. Provider - Dependency Injection & State Management
  3. Riverpod - Modern State Management
  4. Bloc & Cubit - Event-Driven State Management

4.1 What is State Management?

State management in Flutter is the technique used to manage and maintain the state of an application. State can be categorized into two types:

  • Ephemeral (Local) State: Temporary state that only affects a single widget.
  • Global (App-wide) State: State that is shared across multiple widgets or screens.

Flutter offers various state management solutions, each serving different use cases.


4.2 setState() - Managing Local State

setState() is the simplest way to manage state in Flutter. It is suitable for managing UI-related changes in a single widget.


Example 1: Counter App

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}

class CounterPage extends StatefulWidget {
  @override
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  void increment() {
    setState(() {
      count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(child: Text('Count: \$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

Example 2: Toggle Button

bool isOn = false;
setState(() {
  isOn = !isOn;
});

Example 3: Text Field Update

TextEditingController controller = TextEditingController();
setState(() {
  text = controller.text;
});

4.3 Provider: Dependency Injection & State

The provider package is one of the most used state management solutions. It enables dependency injection and separates business logic from UI components.


Example 1: Counter App with Provider

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

class CounterModel extends ChangeNotifier {
  int count = 0;
  void increment() {
    count++;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<CounterModel>(context);
    return Scaffold(
      appBar: AppBar(title: Text('Counter with Provider')),
      body: Center(child: Text('Count: ${counter.count}')),
      floatingActionButton: FloatingActionButton(
        onPressed: counter.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

Example 2: Theme Management

class ThemeModel extends ChangeNotifier {
  bool isDarkMode = false;
  void toggleTheme() {
    isDarkMode = !isDarkMode;
    notifyListeners();
  }
}

Example 3: Shopping Cart

class CartModel extends ChangeNotifier {
  List<String> items = [];
  void addItem(String item) {
    items.add(item);
    notifyListeners();
  }
}

4.4 Riverpod - Modern State Management

Riverpod is an improvement over Provider, offering safer and simpler state management.


Example 1: Counter App with Riverpod

final counterProvider = StateProvider<int>((ref) => 0);

Example 2: Authentication State

final authProvider = StateNotifierProvider<AuthNotifier, bool>((ref) => AuthNotifier());

Example 3: Fetching API Data

final userProvider = FutureProvider<User>((ref) async {
  return fetchUser();
});

4.5 Bloc & Cubit - Event-Driven State Management

Bloc and Cubit provide structured state management using events and states.


Example 1: Counter App with Cubit

class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);
  void increment() => emit(state + 1);
}

Example 2: User Authentication

class AuthCubit extends Cubit<bool> {
  AuthCubit() : super(false);
  void login() => emit(true);
}

Example 3: Todo App

class TodoCubit extends Cubit<List<String>> {
  TodoCubit() : super([]);
  void addTask(String task) {
    state.add(task);
    emit(List.from(state));
  }
}



Leave a Comment


Choose Colour